
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/smp.h>

static u64 read_reg(void)
{
    u64 res;
    asm("mrs %0, sctlr_el1"
        : "=r"(res)
        :);
    return res;
}

static void write_reg(u64 val)
{
    asm("msr sctlr_el1, %0" ::"r"(val));
}

static void smp_print_id(void* t)
{
    unsigned int cur_cpu = smp_processor_id();
    u64 sctlr_el1_val = read_reg();
    printk("cur cpuid: %d, %d, sctlr_el1: %llx\n", cur_cpu, get_cpu(), sctlr_el1_val);
}

static void clear_sctlr_uci(void* t)
{
    smp_print_id(t);
    u64 sctlr_el1_val = read_reg();
    sctlr_el1_val &= ~(1llu << 26); // clean uci, eq uci=0, disable dc/ic... inst exec on el0
    write_reg(sctlr_el1_val);
    smp_print_id(t);
}

static void set_sctlr_uci(void* t)
{
    u64 sctlr_el1_val = read_reg();
    sctlr_el1_val |= (1llu << 26); // set uci, eq uci=0, enable dc/ic... inst exec on el0
    write_reg(sctlr_el1_val);
    smp_print_id(t);
}

static int __init smp_test_init(void)
{
    printk("disalbe sctlr_el1.uci init and start\n");
    // 每一个core都执行
    // on_each_cpu(smp_print_id, NULL, 1);
    on_each_cpu(clear_sctlr_uci, NULL, 1);
    printk("finish on each cpu\n");

    return 0;
}

static void __exit smp_test_exit(void)
{
    on_each_cpu(set_sctlr_uci, NULL, 1);
    printk(KERN_DEBUG "byebye\n");
}

module_init(smp_test_init);
module_exit(smp_test_exit);

MODULE_AUTHOR("ystlong@163.com>");
MODULE_DESCRIPTION("Phytium sctlr_el1 diable dc/ic... instruction demo");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
